/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.service.utils;

import cn.ac.nercis.pes.common.constant.common.AssetConstants;
import cn.ac.nercis.pes.common.constant.common.BaseConstants;
import cn.ac.nercis.pes.common.constant.evaluation.AssetKeyDataReq;
import cn.ac.nercis.pes.common.constant.knowledge.AssetClassification;
import cn.ac.nercis.pes.model.base.AssetField;
import cn.ac.nercis.pes.model.standard.asset.AssetSDTO;
import cn.ac.nercis.pes.repository.mapper.evaluation.AssetMapper;
import cn.ac.nercis.pes.repository.model.evaluation.AssetAttributeDO;
import cn.ac.nercis.pes.repository.model.evaluation.AssetDO;
import cn.ac.nercis.pes.repository.model.knowledge.KmAssetAttributeDO;
import lombok.NonNull;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 重要数据对象辅助类
 * @author zpy
 * @version 1.0.0
 */
public final class AssetUtils {
    private final static String OWNED_APP_ATTR_FIELD = "ownedApp";
    private final static String LOCATION_ATTR_FILE = "location";
    public final static String CONCAT_STR = "-";


    public static String getAssetName(@NonNull AssetDO assetDO){
        if(!isSpecialAssetClass(assetDO)){
            return assetDO.getName();
        }
        String prefixAsset = StringUtils.EMPTY;
        if(isSubBusinessAsset(assetDO) || isKeyDataAsset(assetDO)){
            String ownedApp = getOwnedApp(assetDO.getAttributes());
            if(!StringUtils.equals(ownedApp,assetDO.getName())){
                prefixAsset = ownedApp;
            }
        }else if(isPhySecurityAsset(assetDO)){
            String location = getLocation(assetDO.getAttributes());
            if(!StringUtils.equals(location,assetDO.getName())){
                prefixAsset = location;
            }
        }
        return StringUtils.isBlank(prefixAsset) ? assetDO.getName() :
                prefixAsset.concat(CONCAT_STR).concat(assetDO.getName());
    }

    public static String getQuoteAssetIdByKeyData(String sourceQuoteAssetId, String quoteAssetId, int position){
        if(StringUtils.isBlank(sourceQuoteAssetId)){
            return quoteAssetId;
        }
        List<String> quoteAssetIds = Stream.of(StringUtils.split(sourceQuoteAssetId, BaseConstants.MULTI_SPLIT_CHAR))
                .collect(Collectors.toList());
        if(quoteAssetIds.size()>position){
            quoteAssetIds.set(position,quoteAssetId);
        }else{
            quoteAssetIds.add(quoteAssetId);
        }
        return String.join(BaseConstants.MULTI_SPLIT_CHAR, quoteAssetIds);
    }

    public static String getQuoteAssetIdByKeyData(String quoteAssetId, int position){
        if(StringUtils.isBlank(quoteAssetId)){
            return quoteAssetId;
        }
        List<String> quoteAssetIds = Stream.of(StringUtils.split(quoteAssetId, BaseConstants.MULTI_SPLIT_CHAR))
                .toList();
        if(quoteAssetIds.size()>position){
            return quoteAssetIds.get(position);
        }else{
            return quoteAssetIds.stream()
                    .findFirst()
                    .orElse("");
        }
    }

    public static String getKeyDataReq(String oldReq){
        if(StringUtils.isBlank(oldReq)){
            return oldReq;
        }
       return Stream.of(StringUtils.split(oldReq,AssetConstants.KEY_DATA_REQ_SPLIT))
                .map(AssetKeyDataReq::fromName)
                .filter(Objects::nonNull)
                .map(AssetKeyDataReq::getName)
                .collect(Collectors.joining(AssetConstants.KEY_DATA_REQ_SPLIT));
    }

    public static List<AssetDO> findPhySecurityByLocation(String location,List<AssetDO> sources){
        return sources.stream()
                .filter(a->StringUtils.equals(a.getClassId(), AssetClassification.PHY_SECURITY.getId()))
                .filter(a->{
                    var phySecurity = AssetMapper.INSTANCE.toPhySecurity(a);
                    return Objects.nonNull(phySecurity) && StringUtils.equals(phySecurity.getLocation(),location);
                })
                .toList();
    }
    public static List<AssetDO> findSubBusinessByOwnedApp(String ownedApp,List<AssetDO> sources){
        return sources.stream()
                .filter(a->StringUtils.equals(a.getClassId(),AssetClassification.SUB_BUSINESS.getId()))
                .filter(a->{
                    var subBusiness = AssetMapper.INSTANCE.toSubBusiness(a);
                    return Objects.nonNull(subBusiness) && StringUtils.equals(subBusiness.getOwnedApp(),ownedApp);
                })
                .toList();
    }
    public static List<AssetDO> findKeyDataByOwnedApp(String ownedApp,List<AssetDO> sources){
        return sources.stream()
                .filter(a->StringUtils.equals(a.getClassId(),AssetClassification.KEY_DATA.getId()))
                .filter(a->{
                    var keyData = AssetMapper.INSTANCE.toKeyData(a);
                    return Objects.nonNull(keyData) && StringUtils.equals(keyData.getOwnedApp(),ownedApp);
                })
                .toList();
    }

    public static AssetAttributeDO toAttribute(AssetField asset, KmAssetAttributeDO kmAtt){
        var assetAttributeDO = AssetMapper.INSTANCE.toAssetAttributeDO(kmAtt);
        assetAttributeDO.setValue(asset.getField(kmAtt.getFieldName()));
        return assetAttributeDO;
    }

    private static Boolean isSpecialAssetClass(AssetDO assetDO){
        if(isKeyDataAsset(assetDO)){
            return true;
        }
        if(isSubBusinessAsset(assetDO)){
            return true;
        }
        return isPhySecurityAsset(assetDO);
    }

    private static Boolean isPhySecurityAsset(AssetDO assetDO){
        return StringUtils.equals(assetDO.getClassId(), AssetClassification.PHY_SECURITY.getId());
    }

    private static Boolean isSubBusinessAsset(AssetDO assetDO){
        return StringUtils.equals(assetDO.getClassId(), AssetClassification.SUB_BUSINESS.getId());
    }

    private static Boolean isKeyDataAsset(AssetDO assetDO){
        return StringUtils.equals(assetDO.getClassId(), AssetClassification.KEY_DATA.getId());
    }

    private static String getOwnedApp(Set<AssetAttributeDO> attributes){
        if(CollectionUtils.isEmpty(attributes)){
            return "";
        }
        return attributes.stream()
                .filter(a->StringUtils.equalsIgnoreCase(a.getFieldName(),OWNED_APP_ATTR_FIELD))
                .map(AssetAttributeDO::getValue)
                .filter(StringUtils::isNotBlank)
                .findFirst()
                .orElse("");
    }

    private static String getLocation(Set<AssetAttributeDO> attributes){
        if(CollectionUtils.isEmpty(attributes)){
            return "";
        }
        return attributes.stream()
                .filter(a->StringUtils.equalsIgnoreCase(a.getFieldName(),LOCATION_ATTR_FILE))
                .map(AssetAttributeDO::getValue)
                .filter(StringUtils::isNotBlank)
                .findFirst()
                .orElse("");
    }

    public static void repairImportAssetData(List<AssetSDTO> assets){
        assets.stream()
                .filter(a->StringUtils.equals(a.getClassId(),AssetClassification.KEY_DATA.getId()) && CollectionUtils.isNotEmpty(a.getAttributes()))
                .flatMap(a->a.getAttributes().stream())
                .filter(att->StringUtils.equals(att.getFieldName(),"require") && StringUtils.contains(att.getValue(),"重要数据"))
                .forEach(att->att.setValue(StringUtils.replace(att.getValue(),"重要数据","")));
    }
}